import path from 'path';
import fs from 'fs';
import JSON5 from 'json5';
import {HvigorNode, HvigorPlugin} from '@ohos/hvigor';
import {Hvigor} from '@ohos/hvigor/src/base/external/core/hvigor';
import {OhosPluginId} from "@ohos/hvigor-ohos-plugin";
import {HvigorTaskContext} from "@ohos/hvigor/src/base/vigor/task/interface/hvigor-task";
import {
    blackBackgroundGreenTextLog,
    blackBackgroundRedTextLog,
    blackBackgroundYellowTextLog,
    formatTimestamp,
    getModelTopoMap,
    printDepsMap,
    shouldSkipModule
} from "./utils";
import {execSync} from "node:child_process";
import {OhpmUploader} from "./OhpmUploader";

export interface IbuildParams {
    coverVersion?: string;
    buildMode?: string;
    targetModule: string;
    outHarNameList?: string[];
    outFolderPath?: string;
}

export let buildParams: IbuildParams = {buildMode: 'debug', targetModule: 'all', outHarNameList: []};

export interface HarSdkBuildAllToolsParams {
    runHvigor: Hvigor;
    /**
     * 格式： 127.0.0.1:8088
     */
    repoHost?: string;
    repoUser?: string;
    repoPass?: string;
}

/**
 * harSdkBuildAllTools  –  har SDK包打包工具
 * @param runHvigor Hvigor实例
 */
export function harSdkBuildAllTools(harSdkBuildAllToolsParams: HarSdkBuildAllToolsParams): HvigorPlugin {
    return {
        pluginId: 'harSdkBuildAllTools',
        apply(root: HvigorNode) {
            const runHvigor = harSdkBuildAllToolsParams.runHvigor;
            const toolsVersion = '1.6.8';
            blackBackgroundGreenTextLog(`========== [har SDK包打包工具] 插件版本 v${toolsVersion} ============`);
            blackBackgroundGreenTextLog('===== 该插件将会在hvigor中注册以下任务： =====');
            blackBackgroundGreenTextLog('===== 1.printDepsMap ： 打印模块依赖拓扑图 =====');
            blackBackgroundGreenTextLog('===== 2.harSdkBuildAll ： 构建har SDK包 任务 =====');
            blackBackgroundGreenTextLog('=====   harSdkBuildAll任务包参数：[coverVersion | cv] [buildMode] [targetModule | tm]=====');
            blackBackgroundGreenTextLog('=====   [coverVersion | cv] 是覆盖app.json5中的版本字符串,不传入则按照各个模块的versionName为目标生成版本 =====');
            blackBackgroundGreenTextLog('=====   [buildMode] 是编译模式, debug / release 不传入或者传入非法默认按照debug模式进行,表示编译模块的模式 =====');
            blackBackgroundGreenTextLog('=====   [targetModule | tm] 是目标模块,可以通过 printDepsMap 查看模块的拓扑依赖,模式是all 全部编译 =====');
            blackBackgroundGreenTextLog('=====   [repoHost | rh] 是要上传目标仓库的地址 格式 http://127.0.0.1:8080 =====');
            blackBackgroundGreenTextLog('=====   [repoUser | ru] 是要上传目标仓库的地址 用户名 =====');
            blackBackgroundGreenTextLog('=====   [repoPass | rp] 是要上传目标仓库的地址 密码 =====');
            blackBackgroundGreenTextLog('===== 3.upFolder ： 上传目标文件夹中所有har包 =====');
            blackBackgroundGreenTextLog('=====   [folderPath | fp] 是要上传的目标文件夹 =====');
            blackBackgroundGreenTextLog('=====   [rh、ru、rp]目标仓库参数同上 =====');
            blackBackgroundGreenTextLog('===== 4.setModuleVersions ： 批量设置所有模块版本号 =====');
            blackBackgroundGreenTextLog('=====   [coverVersion | cv] 是覆盖app.json5中的版本字符串,不传入则按照各个模块的versionName为目标生成版本 =====');
            blackBackgroundGreenTextLog('=====   [versionMap | vm] 是 json map 形式选择模块 =====');
            blackBackgroundGreenTextLog('=====   hvigorw setModuleVersions -p versionMap=\'{"@gro/mod1":"2.0.1","@gro/mod2":"2.1.0"}\' =====');

            blackBackgroundGreenTextLog(`===== 处理接收的参数 ====`);
            const cv = runHvigor.getParameter().getExtParam('coverVersion') ?? runHvigor.getParameter().getExtParam('cv');
            const buildMode = runHvigor.getParameter().getExtParam('buildMode');
            const targetModule = runHvigor.getParameter().getExtParam('targetModule') ?? runHvigor.getParameter().getExtParam('tm');
            const ohpmHost = runHvigor.getParameter().getExtParam('repoHost') ?? runHvigor.getParameter().getExtParam('rh');
            const repoUser = runHvigor.getParameter().getExtParam('repoUser') ?? runHvigor.getParameter().getExtParam('ru');
            const repoPass = runHvigor.getParameter().getExtParam('repoPass') ?? runHvigor.getParameter().getExtParam('rp');
            if (ohpmHost) {
                harSdkBuildAllToolsParams.repoHost = ohpmHost;
            }
            if (repoUser) {
                harSdkBuildAllToolsParams.repoUser = repoUser;
            }
            if (repoPass) {
                harSdkBuildAllToolsParams.repoPass = repoPass;
            }
            buildParams = {
                coverVersion: cv,
                buildMode: buildMode ?? 'debug',
                targetModule: targetModule ?? 'all',
                outHarNameList: []
            }
            blackBackgroundGreenTextLog(`===== [buildParams] : ${JSON.stringify(buildParams)} =====`);
            // 核心流程
            // publishAllHar
            //   ├─> buildHarFile
            //   │     ├─> collectVersionMap              // 新增：全局扫描 -> 生成 versions.json
            //   │     └─> <module>:assembleHarWithRewriteCollectHar
            //   │           ├─> <module>:rewriteLocalDeps  // 读取 versions.json 替换 file: -> 远程坐标
            //   │           └─> <module>:collectHarOutputs
            //   │                 └─> <module>:assembleHar   // 系统任务（含 default@PreBuild 等）
            //   │
            //   └─> pushHarToOhpm
            //         └─> buildHarFile

            // 1、向根节点注册 collectVersionMap 收集版本号任务
            blackBackgroundGreenTextLog(`====vvvv 开始进行任务注册 vvvv====`);
            blackBackgroundYellowTextLog(`==== 向主模块注册 collectVersionMap 任务 ====`);
            try {
                runHvigor.getRootNode().registerTask({
                    name: 'collectVersionMap',
                    run(taskContext: HvigorTaskContext) {
                        const buildTime = formatTimestamp();
                        console.log(`===== 【collectVersionMap】 获取每个模块的版本 ${buildTime} =====`);
                        const versionMap = new Map<string, string>();
                        const cv = buildParams.coverVersion;
                        if (cv) {
                            console.log(`===== 【collectVersionMap】 覆盖版本号 ${cv} =====`);
                        }
                        runHvigor.getRootNode().subNodes(sub => {
                            const pkgPath = path.join(sub.getNodePath(), 'oh-package.json5');
                            if (!fs.existsSync(pkgPath)) return;
                            try {
                                let json: any = JSON5.parse(fs.readFileSync(pkgPath, 'utf-8'));
                                const name = json?.name;
                                const ver = json?.version;
                                if (shouldSkipModule(name, buildParams.targetModule ?? 'all', modelTopoMap)) {
                                    blackBackgroundGreenTextLog(`==== 跳过模块: ${name} ====`);
                                    return;
                                }
                                if (cv) {
                                    versionMap.set(name, cv);
                                    console.log(`===== 【${name}:${cv}】版本覆盖-===== `);
                                    /*json.version = cv;
                                    fs.writeFileSync(pkgPath, JSON.stringify(json, null, 2));*/
                                } else {
                                    if (!name || ver) {
                                        versionMap.set(name, ver);
                                        console.log(`===== 【${name}:${ver}】 ===== `);
                                    }
                                }
                            } catch (e) {
                                console.error(`=====  获取模块${sub.getNodeName} 节点模块版本时发生错误：${e} =====`);
                            }
                        });
                        const versionObj = Object.fromEntries(versionMap);
                        const versionJson = JSON.stringify(versionObj);
                        runHvigor.getParameter().setProperty('versionMap', versionJson);
                        console.log(`===== 【collectVersionMap】 versionMapJsonStr: ${versionJson} =====`);
                        // 处理buildMode
                        runHvigor.getParameter().setProperty('buildMode', buildParams.buildMode);
                        console.log(`===== 【collectVersionMap】 buildMode: ${buildParams.buildMode} =====`);
                        /*if(cv){
                            blackBackgroundYellowTextLog(`==== 需要重新同步项目！ ====`);
                            let insSresult = execSync("ohpm install").toString().trim();
                            blackBackgroundGreenTextLog(`==== hvigorw --sync result: ${insSresult} ====`);
                            let syncResult = execSync("hvigorw --sync").toString().trim();
                            blackBackgroundGreenTextLog(`==== hvigorw --sync result: ${syncResult} ====`);
                            blackBackgroundGreenTextLog(`==== 重新同步项目完成！ ====`);
                        }*/
                    }
                });
                blackBackgroundGreenTextLog(`==== 向主模块注册 collectVersionMap 任务成功！ ====`);
            } catch (e) {
                blackBackgroundRedTextLog(`==== 向主模块注册 collectVersionMap 错误！${e} ====`);
            }
            // 模块拓扑图
            const modelTopoMap = getModelTopoMap(runHvigor.getRootNode());

            // 2、为每个模块添加子任务
            // 模块依赖任务字符串数组
            const moduleTaskDeps: string[] = ['collectVersionMap'];
            blackBackgroundYellowTextLog(`==== 为每个模块添加子任务 ====`);
            try {
                runHvigor.getRootNode().subNodes(sub => {
                    blackBackgroundYellowTextLog(`==== 当前模块名: ${sub.getNodeName()} ====`);
                    const nodeName = sub.getNodeName();
                    const nodePkgPath = path.join(sub.getNodeDir().getPath(), 'oh-package.json5');
                    blackBackgroundYellowTextLog(`==== nodePkgPath:${nodePkgPath} ====`);
                    const content = fs.readFileSync(nodePkgPath, 'utf-8');
                    const pkgJson: any = JSON5.parse(content);
                    const nodePkgName: any = pkgJson.name;
                    if (shouldSkipModule(nodePkgName, buildParams.targetModule ?? 'all', modelTopoMap)) {
                        blackBackgroundGreenTextLog(`==== 跳过模块: ${nodeName} ====`);
                        return;
                    }
                    blackBackgroundYellowTextLog(`==== nodePkgName:${nodePkgName} ====`);
                    if (nodeName == 'entry') {
                        blackBackgroundGreenTextLog(`==== entry 模块不参与构建 ====`);
                        return;
                    }

                    if (!sub.getTaskByName('assembleHar')) {
                        console.log(`=====  模块: ${nodeName} 中没有assembleHar 任务=====`);
                        sub.getAllTasks().forEach(task => {
                            console.log(`=====  模块: ${nodeName} 中有 ${task.getName()} 任务=====`);
                        })
                    }
                    // 2、为每个模块添加 rewriteLocalDeps 任务，替换远程版本依赖
                    blackBackgroundYellowTextLog(`=====  向模块: ${nodeName} 添加 rewriteLocalDeps 任务=====`);
                    try {
                        sub.registerTask({
                            name: 'rewriteLocalDeps',
                            run(taskContext: HvigorTaskContext) {
                                // 获取versionMap
                                const versionMapJson = runHvigor.getParameter().getProperty('versionMap');
                                const obj = JSON.parse(versionMapJson);
                                const versionMap = new Map<string, string>(Object.entries(obj));
                                console.log(`=====  【rewriteLocalDeps】 读取到的versionMap :${JSON.stringify(versionMap)} =====`);
                                // 设置versionMap中的 version
                                if (versionMap.has(nodePkgName)) {
                                    blackBackgroundGreenTextLog(`调试模块版本pkgJson.version：${pkgJson.version},taskContext.moduleName:${nodePkgName}`)
                                    blackBackgroundGreenTextLog(`调试模块版本versionMap.get(taskContext.moduleName)：${versionMap.get(nodePkgName)}`)
                                    pkgJson.version = versionMap.get(nodePkgName);
                                }
                                if (pkgJson.dependencies && typeof pkgJson.dependencies === 'object') {
                                    for (const [depName, spec] of Object.entries<string>(pkgJson.dependencies)) {
                                        if (
                                            spec.startsWith('file:') &&
                                            !spec.trim().toLowerCase().endsWith('.har') &&
                                            !spec.trim().toLowerCase().endsWith('.hsp') &&
                                            versionMap &&
                                            versionMap.has(depName)
                                        ) {
                                            pkgJson.dependencies[depName] = versionMap.get(depName);
                                        }
                                    }
                                }
                                // 写回标准 JSON（保留双引号、无多余逗号）
                                fs.writeFileSync(nodePkgPath, JSON.stringify(pkgJson, null, 2) + '\n');
                            }
                        });
                        blackBackgroundGreenTextLog(`=====  向模块: ${nodeName} 添加 rewriteLocalDeps 任务成功！=====`);
                    } catch (e) {
                        blackBackgroundRedTextLog(`=====  向模块: ${nodeName} 添加 rewriteLocalDeps 任务时发生错误：${e}=====`);
                    }

                    // 3、为每个模块添加 collectHarOutputs 任务，收集模块的har产物,移动到项目根目录下outputsdk/version_YYYYMMDD_HHmmss 目录下
                    blackBackgroundYellowTextLog(`=====  3、向模块: ${nodeName} 添加 collectHarOutputs 任务 ${sub.getNodeName()}:assembleHar=====`)
                    try {
                        sub.registerTask({
                            name: 'collectHarOutputs',
                            run(taskContext: HvigorTaskContext) {
                                // 模块目录
                                const moduleDir = taskContext.modulePath;           // 模块目录
                                const rootDir = runHvigor.getRootNode().getNodePath();        // 工程根目录
                                // 2.1 读取并解析 JSON5
                                const appJsonOpt = runHvigor.getRootNode().getContext(OhosPluginId.OHOS_APP_PLUGIN).getAppJsonOpt();
                                let version = '';
                                if (!buildParams.coverVersion) {
                                    version = appJsonOpt['app']['versionName'];
                                    console.log(`[har-sdk-build-plugin] 未设置版本号，采用app版本号：${version}`);
                                } else {
                                    version = buildParams.coverVersion;
                                }
                                // const ts = runHvigor.getParameter().getExtParam('buildTime')??formatTimestamp();
                                // 模块的 har 输出目录（hvigor 默认路径）
                                const harOutDir = path.join(moduleDir, 'build', 'default', 'outputs', 'default');
                                if (!fs.existsSync(harOutDir)) {
                                    console.error(`[collectHarOutputs] 模块 ${moduleDir} 未找到产物目录 ${harOutDir}`);
                                    return;
                                }
                                console.log(`[collectHarOutputs] 模块 ${moduleDir} 找到产物目录 ${harOutDir}`);
                                // 目标聚拢目录,合法化目标模块名
                                const targetModuleName = buildParams.targetModule.replace(/[^a-zA-Z0-9@]/g, '_');
                                const targetDir = path.join(rootDir, 'outputsdk', `${targetModuleName}_${version}_building`);
                                runHvigor.getParameter().setProperty('targetDir', targetDir);
                                fs.mkdirSync(targetDir, {recursive: true});

                                // 遍历复制
                                const files = fs.readdirSync(harOutDir).filter(f => f.endsWith('.har'));
                                if (files.length === 0) {
                                    console.error(`[collectHarOutputs] 模块 ${moduleDir} 没有 .har 产物`);
                                }
                                for (const f of files) {
                                    const src = path.join(harOutDir, f);
                                    const dst = path.join(targetDir, f);
                                    fs.copyFileSync(src, dst);
                                    console.log(`[collectHarOutputs] ${src} -> ${dst}`);
                                    buildParams.outHarNameList?.push(f);
                                }
                            },
                            dependencies: [`assembleHar`]
                        });
                        blackBackgroundGreenTextLog(`=====  向模块: ${nodeName} 添加 collectHarOutputs 任务成功！=====`);
                    } catch (e) {
                        blackBackgroundRedTextLog(`=====  向模块: ${nodeName} 添加 collectHarOutputs 任务时发生错误：${e}=====`);
                    }

                    // 4、为每个模块添加 assembleHarWithRewriteCollectHar 聚合任务，依赖 rewriteLocalDeps 和 collectHarOutputs
                    blackBackgroundYellowTextLog(`=====  4、向模块: ${nodeName} 添加 assembleHarWithRewriteCollectHar 聚合任务 ${nodeName}:assembleHarWithRewriteCollectHar=====`)
                    try {
                        sub.registerTask({
                            name: 'assembleHarWithRewriteCollectHar',
                            run() {
                                console.log(`[assembleHarWithRewriteCollectHar] 模块 ${nodeName} 运行任务`);
                            },
                            dependencies: [`rewriteLocalDeps`, `collectHarOutputs`]
                        });
                        blackBackgroundGreenTextLog(`=====  向模块: ${nodeName} 添加 assembleHarWithRewriteCollectHar 聚合任务成功！=====`);
                    } catch (e) {
                        blackBackgroundRedTextLog(`=====  向模块: ${nodeName} 添加 assembleHarWithRewriteCollectHar 聚合任务时发生错误：${e}=====`);
                    }
                    // 模块依赖字符串数组
                    moduleTaskDeps.push(`${nodeName}:assembleHarWithRewriteCollectHar`);
                });
                blackBackgroundGreenTextLog(`==== 为每个模块添加子任务成功！ ====`);
                blackBackgroundGreenTextLog(`==== 模块依赖数组：${JSON.stringify(moduleTaskDeps)} ====`);
            } catch (e) {
                blackBackgroundRedTextLog(`==== 为每个模块添加子任务错误！${e} ====`);
            }

            // 5、向根节点注册 buildHarFile 聚合任务，依赖 collectVersionMap 和每个模块的 assembleHarWithRewriteCollectHar 任务
            // 5.1、 构造模块
            blackBackgroundYellowTextLog(`==== 向跟节点注册buildHarFile任务 ====`);
            try {
                runHvigor.getRootNode().registerTask({
                    name: 'buildHarFile',
                    run() {
                        console.log(`[buildHarFile] 运行任务`);
                    },
                    dependencies: moduleTaskDeps,
                    afterRun: (taskContext: HvigorTaskContext) => {
                        const targetDir = runHvigor.getParameter().getProperty('targetDir');
                        blackBackgroundGreenTextLog(`[buildHarFile] 聚合任务完成`)
                        // 1) 取目录 & 时间戳
                        const paramSvc = runHvigor.getParameter();
                        const targetDirRaw = paramSvc.getProperty?.('targetDir') || process.env.targetDir || '';
                        if (!targetDirRaw) {
                            console.log(`[buildHarFile] 未提供 targetDir，跳过重命名`);
                            return;
                        }

                        // 共用同一批构建时间戳，若外部已设置则复用
                        const ts = `${buildParams.buildMode}_${formatTimestamp()}`;

                        // 2) 校验目录存在
                        if (!fs.existsSync(targetDir) || !fs.statSync(targetDir).isDirectory()) {
                            console.log(`[buildHarFile] 目标目录不存在或不是目录：${targetDir}`);
                            return;
                        }

                        // 3) 计算新目录名：将最后一级目录名中的 'building' 替换为时间戳
                        const parent = path.dirname(targetDir);
                        const base = path.basename(targetDir);

                        let newBase = base.replace(/building/gi, ts);
                        if (newBase === base) {
                            // 没有包含 'building'；可选择追加时间戳避免无变化
                            newBase = `${base}_${ts}`;
                        }

                        const newDir = path.join(parent, newBase);

                        // 4) 若目标已存在，附加一个短随机串避免覆盖
                        let finalDir = newDir;
                        if (fs.existsSync(finalDir)) {
                            finalDir = `${newDir}_${Math.random().toString(36).slice(2, 6)}`;
                        }

                        // 5) 执行重命名
                        try {
                            fs.renameSync(targetDir, finalDir);
                            console.log(`[buildHarFile] 重命名完成：\n  from: ${targetDir}\n  to  : ${finalDir}`);
                            buildParams.outFolderPath = finalDir;
                            // 可选：把新的路径写回扩展参数，供后续任务/日志使用
                            // taskContext.setExtParam?.('finalTargetDir', finalDir);
                        } catch (e: any) {
                            console.error(`[buildHarFile] 重命名失败：${e?.message || e}`);
                        }
                    }
                });
                blackBackgroundGreenTextLog(`==== 向跟节点注册buildHarFile任务成功！ ====`);
            } catch (e) {
                blackBackgroundRedTextLog(`==== 向跟节点注册buildHarFile任务错误！${e} ====`);
            }

            // 6、向根节点注册 pushHarToOhpm 推送har包任务，依赖 buildHarFile
            blackBackgroundYellowTextLog(`==== 向根节点注册pushHarToOhpm任务 ====`);
            try {
                runHvigor.getRootNode().registerTask({
                    name: 'pushHarToOhpm',
                    async run() {
                        blackBackgroundGreenTextLog(`[pushHarToOhpm] 上传至私仓`);
                        let result = execSync("ohpm -v").toString().trim();
                        blackBackgroundGreenTextLog(`[pushHarToOhpm] ohpm版本：${result}`);
                        console.log(`输出文件夹： ${buildParams.outFolderPath}`);
                        console.log(`输出文件名列表： ${buildParams.outHarNameList}`);
                        console.log(`目标仓库地址： ${harSdkBuildAllToolsParams.repoHost}`);
                        console.log(`上传用户： ${harSdkBuildAllToolsParams.repoUser}`);
                        if (buildParams.outHarNameList == undefined || buildParams.outHarNameList.length == 0) {
                            blackBackgroundRedTextLog(`[pushHarToOhpm] 输出文件列表为空！终止上传`);
                            return;
                        }
                        if (harSdkBuildAllToolsParams.repoHost == undefined) {
                            blackBackgroundRedTextLog(`[pushHarToOhpm] 目标仓库地址未设置！终止上传`);
                            return;
                        }
                        if (harSdkBuildAllToolsParams.repoUser == undefined) {
                            blackBackgroundRedTextLog(`[pushHarToOhpm] 上传用户名未设置！终止上传`);
                            return;
                        }
                        if (harSdkBuildAllToolsParams.repoPass == undefined) {
                            blackBackgroundRedTextLog(`[pushHarToOhpm] 未提供上传用户密码！终止上传`);
                            return;
                        }
                        const fileList = buildParams.outHarNameList.map(name =>
                            path.join(buildParams.outFolderPath!!, name)   // 自动适配 Windows / Linux 分隔符
                        );
                        // 上传
                        const {success, failed} = await OhpmUploader.loginAndUploadBatch(
                            harSdkBuildAllToolsParams.repoHost,
                            harSdkBuildAllToolsParams.repoUser,
                            harSdkBuildAllToolsParams.repoPass,
                            fileList
                        );
                    },
                    dependencies: ['buildHarFile']
                });
                blackBackgroundGreenTextLog(`==== 向根节点注册pushHarToOhpm任务成功！ ====`);
            } catch (e) {
                blackBackgroundRedTextLog(`==== 向根节点注册pushHarToOhpm任务错误！${e} ====`);
            }

            // 7、向节点注册 harSdkBuildAll 任务,依赖 pushHarToOhpm
            blackBackgroundYellowTextLog(`==== 向根节点注册harSdkBuildAll任务 ====`);
            try {
                runHvigor.getRootNode().registerTask({
                    name: 'harSdkBuildAll',
                    run() {

                    },
                    dependencies: ['pushHarToOhpm']
                });
                blackBackgroundGreenTextLog(`==== 向根节点注册harSdkBuildAll任务成功！ ====`);
            } catch (e) {
                blackBackgroundRedTextLog(`==== 向根节点注册harSdkBuildAll任务错误！${e} ====`);
            }

            // 8、向根节点注册 打印模块依赖拓扑图任务：
            try {
                runHvigor.getRootNode().registerTask({
                    name: 'printDepsMap',
                    run() {
                        // 打印模块拓扑图
                        printDepsMap(root);
                    },
                });
                blackBackgroundGreenTextLog(`==== 向根节点注册 printDepsMap 任务成功！ ====`);
            } catch (e) {
                blackBackgroundRedTextLog(`==== 向根节点注册 printDepsMap 任务错误！${e} ====`);
            }
            // 9、向根节点注册 upFolder 任务：上传指定目录下的所有 .har
            try {
                runHvigor.getRootNode().registerTask({
                    name: 'upFolder',
                    async run() {
                        blackBackgroundGreenTextLog(`[upFolder] 开始上传目录中的 .har 文件`);

                        // 读取参数（命令行：-p folderPath=... -p repoHost=... -p repoUser=... -p repoPass=...）
                        const folderPath =
                            runHvigor.getParameter().getExtParam('folderPath')
                            ?? runHvigor.getParameter().getExtParam('fp');

                        const repoHost =
                            runHvigor.getParameter().getExtParam('repoHost')
                            ?? runHvigor.getParameter().getExtParam('rh')
                            ?? harSdkBuildAllToolsParams.repoHost;

                        const repoUser =
                            runHvigor.getParameter().getExtParam('repoUser')
                            ?? runHvigor.getParameter().getExtParam('ru')
                            ?? harSdkBuildAllToolsParams.repoUser;

                        const repoPass =
                            runHvigor.getParameter().getExtParam('repoPass')
                            ?? runHvigor.getParameter().getExtParam('rp')
                            ?? harSdkBuildAllToolsParams.repoPass;

                        // 校验
                        if (!folderPath) {
                            blackBackgroundRedTextLog(`[upFolder] 缺少参数：folderPath，示例：-p folderPath=x:/outputs`);
                            return;
                        }
                        if (!repoHost) {
                            blackBackgroundRedTextLog(`[upFolder] 缺少参数：repoHost`);
                            return;
                        }
                        if (!repoUser) {
                            blackBackgroundRedTextLog(`[upFolder] 缺少参数：repoUser`);
                            return;
                        }
                        if (!repoPass) {
                            blackBackgroundRedTextLog(`[upFolder] 缺少参数：repoPass`);
                            return;
                        }

                        const absFolder = path.resolve(String(folderPath));
                        if (!fs.existsSync(absFolder) || !fs.statSync(absFolder).isDirectory()) {
                            blackBackgroundRedTextLog(`[upFolder] 目录不存在或不是目录：${absFolder}`);
                            return;
                        }

                        // 收集要上传的文件 —— 默认只上传 .har；如需全部文件，去掉 filter 即可
                        const all = fs.readdirSync(absFolder);
                        const fileList = all
                            .filter(n => n.toLowerCase().endsWith('.har'))
                            .map(n => path.join(absFolder, n));

                        if (fileList.length === 0) {
                            blackBackgroundYellowTextLog(`[upFolder] 目录下没有 .har 文件：${absFolder}`);
                            return;
                        }

                        blackBackgroundGreenTextLog(`[upFolder] 发现 ${fileList.length} 个 .har 待上传`);
                        fileList.forEach((f, i) => console.log(`  ${i + 1}. ${f}`));

                        // 执行上传（串行）
                        const {success, failed} = await OhpmUploader.loginAndUploadBatch(
                            String(repoHost),
                            String(repoUser),
                            String(repoPass),
                            fileList
                        );
                    }
                });
                blackBackgroundGreenTextLog(`==== 向根节点注册 upFolder 任务成功！ ====`);
            } catch (e) {
                blackBackgroundRedTextLog(`==== 向根节点注册 upFolder 任务错误！${e} ====`);
            }

            // 9、向根节点注册 setModuleVersions 批量设置所有模块版本号
            // 用法：
            // hvigorw setModuleVersions -p cv=2.1.0
            // hvigorw setModuleVersions -p versionMap='{"@gro/mod1":"2.0.1","@gro/mod2":"2.1.0"}'
            try {
                runHvigor.getRootNode().registerTask({
                    name: 'setModuleVersions',
                    run() {
                        const params = runHvigor.getParameter();

                        // 统一版本（全局）：优先读取你原来的 cv / coverVersion
                        const coverVersion =
                            params.getExtParam('cv') ??
                            params.getExtParam('coverVersion') ??
                            undefined;

                        // 按模块覆盖：JSON 字符串 -> Map<string,string>
                        const versionMapStr =
                            params.getExtParam('versionMap') ??
                            params.getExtParam('vm') ??
                            undefined;

                        const targetModuleParam =
                            params.getExtParam('targetModule') ??
                            params.getExtParam('tm') ??
                            'all';

                        if (!coverVersion && !versionMapStr) {
                            blackBackgroundRedTextLog(`[setModuleVersions] 需要提供 -p cv=... 或 -p versionMap='{"pkg":"ver"}'`);
                            return;
                        }

                        let overrideMap = new Map<string, string>();
                        if (versionMapStr) {
                            try {
                                const obj = JSON.parse(versionMapStr as string) as Record<string, string>;
                                overrideMap = new Map<string, string>(Object.entries(obj));
                            } catch (e) {
                                blackBackgroundRedTextLog(`[setModuleVersions] 解析 versionMap 失败：${e}`);
                                return;
                            }
                        }

                        const changed: Array<{ name: string; old?: string; next: string; file: string }> = [];
                        const skipped: string[] = [];

                        runHvigor.getRootNode().subNodes(sub => {
                            const pkgPath = path.join(sub.getNodePath(), 'oh-package.json5');
                            if (!fs.existsSync(pkgPath)) return;

                            try {
                                const json: any = JSON5.parse(fs.readFileSync(pkgPath, 'utf-8'));
                                const name = json?.name as string | undefined;
                                const oldVer = json?.version as string | undefined;
                                if (!name) return;

                                // 过滤：是否跳过该模块
                                if (shouldSkipModule(name, targetModuleParam, modelTopoMap)) {
                                    skipped.push(name);
                                    return;
                                }

                                // 计算目标版本：模块级覆盖优先，其次全局 cv
                                const nextVer = overrideMap.get(name) ?? coverVersion;
                                if (!nextVer) {
                                    blackBackgroundYellowTextLog(`[setModuleVersions] 跳过 ${name}：无可用目标版本（未命中 versionMap 且未提供 cv）`);
                                    return;
                                }

                                if (oldVer === nextVer) {
                                    blackBackgroundYellowTextLog(`[setModuleVersions] 保持不变 ${name}@${oldVer}`);
                                    return;
                                }

                                // 直接写回
                                json.version = nextVer;
                                fs.writeFileSync(pkgPath, JSON.stringify(json, null, 2));

                                blackBackgroundGreenTextLog(`[setModuleVersions] ${name}: ${oldVer ?? '(none)'}  ->  ${nextVer}`);
                                changed.push({ name, old: oldVer, next: nextVer, file: pkgPath });

                            } catch (e) {
                                blackBackgroundRedTextLog(`[setModuleVersions] 处理 ${pkgPath} 失败：${e}`);
                            }
                        });

                        // 总结
                        console.log('\n===== setModuleVersions 结果 =====');
                        console.log(`目标过滤：${targetModuleParam}`);
                        if (changed.length) {
                            console.log(`✅ 修改 ${changed.length} 个模块:`);
                            changed.forEach((it, i) =>
                                console.log(`  ${i + 1}. ${it.name}: ${it.old ?? '(none)'} -> ${it.next}  (${it.file})`)
                            );
                        } else {
                            console.log(`ℹ️ 没有模块被修改`);
                        }
                        if (skipped.length) {
                            console.log(`🟨 跳过 ${skipped.length} 个模块:`);
                            skipped.forEach(n => console.log(`  - ${n}`));
                        }
                        console.log('=================================\n');

                        // 把最终版本映射写回参数服务（Map 风格）
                        const finalMap = new Map<string, string>();
                        // 先放 overrideMap 中的键值
                        overrideMap.forEach((v, k) => finalMap.set(k, v));
                        // 对于本次修改成功的模块，覆盖为写入后的版本
                        changed.forEach(it => finalMap.set(it.name, it.next));

                        // 存为 JSON 字符串，供 rewriteLocalDeps 使用
                        const finalObj = Object.fromEntries(finalMap);
                        params.setProperty('versionMap', JSON.stringify(finalObj));
                        console.log(`[setModuleVersions] 已写入 versionMap 参数：${JSON.stringify(finalObj)}`);
                    }
                });
                blackBackgroundGreenTextLog(`==== 向根节点注册 setModuleVersions 任务成功！ ====`);
            } catch (e) {
                blackBackgroundRedTextLog(`==== 向根节点注册 setModuleVersions 任务错误！${e} ====`);
            }

        }
    }
}